﻿namespace MobileTrack.Web.Controllers
{
    using System;
    using System.Data.Entity;
    using System.Globalization;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Web.Mvc;
    using System.Web.Security;
    using MobileTrack.Core.Data;
    using MobileTrack.Core.Model;
    using MobileTrack.Web.Properties;
    using MobileTrack.Web.ViewModels;

    public class ImeisController : BaseController
    {
        public ImeisController(IRepositories repositories, MembershipProvider membershipProvider, RoleProvider roleProvider)
            : base(repositories, membershipProvider, roleProvider)
        {
        }

        public ActionResult Index(string filter)
        {
            this.ViewBag.Filter = filter;

            this.ViewBag.OperadoresFilter = this.Repositories
                .Marcas
                .All
                .Where(m => m.EsOperador == true)
                .Select(m => m.Nombre)
                .AsEnumerable();

            this.ViewBag.EstadosFilter = new[] { "Pendiente", "En Deposito", "En Transito", "Disponible Venta", "Vendido", "Dañado" };

            this.ViewBag.UbicacionesFilter = this.Repositories
                .Sucursales
                .All
                .AsEnumerable()
                .Select(s => s.Nombre);

            return this.View();
        }

        public ActionResult AssociateImei()
        {
            this.LoadEstadosAfterAssociate();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_AssociateImei");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult AssociateImei(AssociateImeiViewModel asociacion)
        {
            if (this.ModelState.IsValid)
            {
                var celular = this.Repositories
                    .Celulares
                    .All
                    .Include(c => c.Seguimientos)
                    .Single(c => c.Id == asociacion.Id);

                if (celular != null)
                {
                    var imeiCount = this.Repositories.Celulares.All.Where(c => c.Imei == asociacion.Imei).Count();

                    if (imeiCount == 0)
                    {
                        var lastSeg = celular.LastSeguimiento;

                        if (asociacion.Fecha >= lastSeg.Fecha)
                        {
                            celular.Imei = asociacion.Imei;

                            var seg = new Seguimiento
                            {
                                CelularId = asociacion.Id,
                                Comprobante = lastSeg.Comprobante,
                                EstadoInt = asociacion.EstadoInt,
                                Fecha = asociacion.Fecha,
                                ResponsableId = this.CurrentUserKey,
                                Sucursal = lastSeg.Sucursal
                            };

                            this.Repositories.Seguimientos.Add(seg);
                            this.Repositories.SaveChanges();

                            return this.Json(new { saved = true });
                        }
                        else
                        {
                            this.ModelState.AddModelError("Fecha", Resources.InvalidAssociationDateError);
                        }
                    }
                    else
                    {
                        this.ModelState.AddModelError("Imei", Resources.DuplicatedImei);
                    }
                }
            }

            this.LoadEstadosAfterAssociate((Estado)asociacion.EstadoInt);

            return this.PartialView("_AssociateImei", asociacion);
        }

        public ActionResult BulkSend()
        {
            this.LoadAllSucursales();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_BulkSend");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult BulkSend(BulkSendViewModel envioLote)
        {
            if (this.ModelState.IsValid)
            {
                var ids = envioLote.Ids.Split(',');
                var errorsPresent = false;

                foreach (string id in ids)
                {
                    var parsedId = long.Parse(id, NumberStyles.Integer, CultureInfo.InvariantCulture);
                    var lastSeg = this.Repositories
                        .Seguimientos
                        .All
                        .Where(s => s.CelularId == parsedId)
                        .OrderBy(s => s.Fecha)
                        .ThenBy(s => s.Id)
                        .AsEnumerable()
                        .LastOrDefault();

                    if ((lastSeg != null) && (envioLote.FechaEnv >= lastSeg.Fecha))
                    {
                        var suc = this.Repositories.Sucursales.All.Single(s => s.Id == envioLote.SucursalId);

                        var seg = new Seguimiento
                        {
                            CelularId = parsedId,
                            Comprobante = envioLote.Comprobante,
                            EstadoInt = (int)Estado.EnTransito,
                            Fecha = envioLote.FechaEnv,
                            ResponsableId = this.CurrentUserKey,
                            Sucursal = suc
                        };

                        this.Repositories.Seguimientos.Add(seg);
                    }
                    else
                    {
                        this.ModelState.AddModelError("FechaEnv", Resources.InvalidSendReceiveDateError);
                        errorsPresent = true;
                    }
                }

                if (!errorsPresent)
                {
                    this.Repositories.SaveChanges();
                    return this.Json(new { saved = true });
                }
            }

            this.LoadAllSucursales(envioLote.SucursalId);

            return this.PartialView("_BulkSend", envioLote);
        }

        public ActionResult BulkReceive()
        {
            this.LoadEstadosAfterReceiveOrReturn();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_BulkReceive");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult BulkReceive(BulkReceiveViewModel reciboLote)
        {
            if (this.ModelState.IsValid)
            {
                var ids = reciboLote.Ids.Split(',');
                var errorsPresent = false;

                foreach (string id in ids)
                {
                    var parsedId = long.Parse(id, NumberStyles.Integer, CultureInfo.InvariantCulture);
                    var lastSeg = this.Repositories
                        .Seguimientos
                        .All
                        .Where(s => s.CelularId == parsedId)
                        .OrderBy(s => s.Fecha)
                        .ThenBy(s => s.Id)
                        .AsEnumerable()
                        .LastOrDefault();

                    if ((lastSeg != null) && (reciboLote.FechaRec >= lastSeg.Fecha))
                    {
                        var seg = new Seguimiento
                        {
                            CelularId = parsedId,
                            Comprobante = lastSeg.Comprobante,
                            EstadoInt = reciboLote.EstadoIntRec,
                            Fecha = reciboLote.FechaRec,
                            ResponsableId = this.CurrentUserKey,
                            Sucursal = lastSeg.Sucursal
                        };

                        this.Repositories.Seguimientos.Add(seg);
                    }
                    else
                    {
                        this.ModelState.AddModelError("FechaRec", Resources.InvalidSendReceiveDateError);
                        errorsPresent = true;
                    }
                }

                if (!errorsPresent)
                {
                    this.Repositories.SaveChanges();
                    return this.Json(new { saved = true });
                }
            }

            this.LoadEstadosAfterReceiveOrReturn((Estado)reciboLote.EstadoIntRec);

            return this.PartialView("_BulkReceive", reciboLote);
        }

        public ActionResult SendImei()
        {
            this.LoadAllSucursales();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_SendImei");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult SendImei(SendImeiViewModel envio)
        {
            if (this.ModelState.IsValid)
            {
                var lastSeg = this.Repositories
                    .Seguimientos
                    .All
                    .Where(s => s.CelularId == envio.Id)
                    .OrderBy(s => s.Fecha)
                    .ThenBy(s => s.Id)
                    .AsEnumerable()
                    .LastOrDefault();

                if ((lastSeg != null) && (envio.FechaEnv >= lastSeg.Fecha))
                {
                    var suc = this.Repositories.Sucursales.All.Single(s => s.Id == envio.SucursalId);

                    var seg = new Seguimiento
                    {
                        CelularId = envio.Id,
                        Comprobante = envio.Comprobante,
                        EstadoInt = (int)Estado.EnTransito,
                        Fecha = envio.FechaEnv,
                        ResponsableId = this.CurrentUserKey,
                        Sucursal = suc
                    };

                    this.Repositories.Seguimientos.Add(seg);
                    this.Repositories.SaveChanges();

                    return this.Json(new { saved = true });
                }
                else
                {
                    this.ModelState.AddModelError("FechaEnv", Resources.InvalidSendReceiveDateError);
                }
            }

            this.LoadAllSucursales(envio.SucursalId);

            return this.PartialView("_SendImei", envio);
        }

        public ActionResult ReceiveImei()
        {
            this.LoadEstadosAfterReceiveOrReturn();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_ReceiveImei");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult ReceiveImei(ReceiveImeiViewModel recepcion)
        {
            if (this.ModelState.IsValid)
            {
                var lastSeg = this.Repositories
                    .Seguimientos
                    .All
                    .Where(s => s.CelularId == recepcion.Id)
                    .OrderBy(s => s.Fecha)
                    .ThenBy(s => s.Id)
                    .AsEnumerable()
                    .LastOrDefault();

                if ((lastSeg != null) && (recepcion.FechaRec >= lastSeg.Fecha))
                {
                    var seg = new Seguimiento
                    {
                        CelularId = recepcion.Id,
                        Comprobante = recepcion.Comprobante,
                        EstadoInt = recepcion.EstadoIntRec,
                        Fecha = recepcion.FechaRec,
                        ResponsableId = this.CurrentUserKey,
                        Sucursal = lastSeg.Sucursal
                    };

                    this.Repositories.Seguimientos.Add(seg);
                    this.Repositories.SaveChanges();

                    return this.Json(new { saved = true });
                }
                else
                {
                    this.ModelState.AddModelError("FechaRec", Resources.InvalidSendReceiveDateError);
                }
            }

            this.LoadEstadosAfterReceiveOrReturn((Estado)recepcion.EstadoIntRec);
            
            return this.PartialView("_ReceiveImei", recepcion);
        }

        public ActionResult SellImei(long id)
        {
            var celular = this.Repositories.Celulares.All.Include(c => c.Marca).Single(c => c.Id == id);

            this.LoadAbonosFor(celular);

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_SellImei");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult SellImei(SellImeiViewModel venta)
        {
            var celular = this.Repositories.Celulares.All.Include(c => c.Marca).Single(c => c.Id == venta.Id);

            if (this.ModelState.IsValid)
            {
                var lastSeg = celular.LastSeguimiento;

                if ((lastSeg != null) && (venta.FechaVenta >= lastSeg.Fecha))
                {
                    var seg = new Seguimiento
                    {
                        CelularId = venta.Id,
                        Comprobante = venta.Comprobante,
                        EstadoInt = (int)Estado.Vendido,
                        Fecha = venta.FechaVenta,
                        ResponsableId = this.CurrentUserKey,
                        Sucursal = lastSeg.Sucursal
                    };

                    this.Repositories.Seguimientos.Add(seg);

                    if (venta.AbonoId > 0)
                    {
                        var newVenta = new Venta
                        {
                            AbonoId = venta.AbonoId,
                            Activado = false,
                            CelularId = venta.Id,
                            SeguimientoId = seg.Id
                        };

                        this.Repositories.Ventas.Add(newVenta);
                    }

                    this.Repositories.SaveChanges();

                    return this.Json(new { saved = true });
                }
                else
                {
                    this.ModelState.AddModelError("FechaVenta", Resources.InvalidSendReceiveDateError);
                }
            }

            this.LoadAbonosFor(celular);

            return this.PartialView("_SellImei", venta);
        }

        public ActionResult ReturnImei()
        {
            this.LoadEstadosAfterReceiveOrReturn();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_ReturnImei");
            }

            return this.View();
        }

        [HttpPost]
        public ActionResult ReturnImei(ReturnImeiViewModel devolucion)
        {
            if (this.ModelState.IsValid)
            {
                var lastSeg = this.Repositories
                    .Seguimientos
                    .All
                    .Where(s => s.CelularId == devolucion.Id)
                    .OrderBy(s => s.Fecha)
                    .ThenBy(s => s.Id)
                    .AsEnumerable()
                    .LastOrDefault();

                if ((lastSeg != null) && (devolucion.FechaDev >= lastSeg.Fecha) && (lastSeg.Estado == Estado.Vendido))
                {
                    var seg = new Seguimiento
                    {
                        CelularId = devolucion.Id,
                        Comprobante = devolucion.Comprobante,
                        EstadoInt = devolucion.EstadoIntDev,
                        Fecha = devolucion.FechaDev,
                        ResponsableId = this.CurrentUserKey,
                        Sucursal = lastSeg.Sucursal
                    };

                    this.Repositories.Seguimientos.Add(seg);
                    this.Repositories.SaveChanges();

                    return this.Json(new { saved = true });
                }
                else
                {
                    this.ModelState.AddModelError("FechaDev", Resources.InvalidSendReceiveDateError);
                }
            }

            this.LoadEstadosAfterReceiveOrReturn((Estado)devolucion.EstadoIntDev);

            return this.PartialView("_ReturnImei", devolucion);
        }

        public ActionResult List(string filter, int page, int rows)
        {
            var query = this.Repositories
                .Celulares
                .All
                .Include(c => c.Marca)
                .Include(c => c.Seguimientos)
                .OrderBy(c => c.FechaIngreso);

            if (!string.IsNullOrWhiteSpace(filter))
            {
                query = Filter(query, filter);
            }

            int totalRows = query.Count();
            int totalPages = (totalRows == 0) ? 1 : (int)Math.Ceiling((double)totalRows / (double)rows);
            page = (page < 1) ? 1 : page;

            var cellPhones = query
                .Skip((page - 1) * rows)
                .Take(rows)
                .ToArray()
                .Select(c => new CelularViewModel(c, this.User));

            return this.Json(new { total = totalPages, page = page, records = totalRows, rows = cellPhones }, JsonRequestBehavior.AllowGet);
        }

        private static IOrderedQueryable<Celular> Filter(IOrderedQueryable<Celular> celulares, string filter)
        {
            var filterRegex = new Regex(@"([^\+]+):([^\+]+)\+?");
            MatchCollection fields = filterRegex.Matches(filter);
            foreach (Match m in fields)
            {
                switch (m.Groups[1].Value.ToUpperInvariant())
                {
                    case "IMEI":
                        long imei;
                        if (long.TryParse(m.Groups[2].Value, out imei))
                        {
                            celulares = celulares
                                .Where(f => f.Imei == imei)
                                .OrderBy(c => c.FechaIngreso);
                        }

                        break;
                    case "PRODUCTO":
                        var desc = m.Groups[2].Value;
                        celulares = celulares
                            .Where(f => f.Descripcion.Contains(desc))
                            .OrderBy(c => c.FechaIngreso);

                        break;
                    case "INGRESO":
                        DateTime ingreso;
                        if (DateTime.TryParse(m.Groups[2].Value, out ingreso))
                        {
                            celulares = celulares
                                .Where(f => f.FechaIngreso == ingreso)
                                .OrderBy(c => c.FechaIngreso);
                        }

                        break;
                    case "OPERADOR":
                        var oper = m.Groups[2].Value;
                        if (!string.IsNullOrWhiteSpace(oper) && oper.Equals("liberado", StringComparison.OrdinalIgnoreCase))
                        {
                            celulares = celulares
                                .Where(f => !f.Marca.EsOperador)
                                .OrderBy(c => c.FechaIngreso);
                        }
                        else
                        {
                            celulares = celulares
                                .Where(f => f.Marca.Nombre.Contains(oper))
                                .OrderBy(c => c.FechaIngreso);
                        }

                        break;
                    case "ESTADO":
                        var estado = ModelHelper.ParseEstado(m.Groups[2].Value);
                        if (estado != null)
                        {
                            celulares = celulares
                                .Where(f => f.Seguimientos.OrderByDescending(s => s.Fecha).ThenByDescending(s => s.Id).FirstOrDefault().EstadoInt == estado)
                                .OrderBy(c => c.FechaIngreso);
                        }

                        break;
                    case "UBICACION":
                        var ubic = m.Groups[2].Value;
                        celulares = celulares
                            .Where(f => f.Seguimientos.OrderByDescending(s => s.Fecha).ThenByDescending(s => s.Id).FirstOrDefault().Sucursal.Nombre.Contains(ubic))
                            .OrderBy(c => c.FechaIngreso);

                        break;
                    case "COMPROBANTE":
                        var cbte = m.Groups[2].Value;
                        celulares = celulares
                            .Where(f => (f.Seguimientos.Where(s => s.Comprobante.Contains(cbte)).Count() > 0))
                            .OrderBy(c => c.FechaIngreso);

                        break;

                    default:
                        break;
                }
            }

            return celulares;
        }

        private static SelectListItem CreateEstadoListItem(Estado estado, Estado? selectedEstado = null)
        {
            return new SelectListItem
            {
                Text = ModelHelper.ToString(estado),
                Value = ((int)estado).ToString(CultureInfo.InvariantCulture),
                Selected = selectedEstado.HasValue && (estado == selectedEstado.Value)
            };
        }

        private void LoadAbonosFor(Celular celular)
        {
            if (!celular.Marca.EsOperador)
            {
                this.ViewBag.AbonoList = new[] { new SelectListItem { Value = "0", Text = Resources.AbonoLiberado, Selected = true } };
            }
            else
            {
                this.ViewBag.AbonoList = this.Repositories
                    .Abonos
                    .All
                    .Where(a => a.MarcaId == celular.MarcaId)
                    .AsEnumerable()
                    .Select(
                        s => new SelectListItem
                        {
                            Text = s.Descripcion,
                            Value = s.Id.ToString(CultureInfo.InvariantCulture)
                        });
            }
        }

        private void LoadAllSucursales(long? selectedSucursalId = null)
        {
            this.ViewBag.SucursalList = this.Repositories
                .Sucursales
                .All
                .AsEnumerable()
                .Select(
                    s => new SelectListItem
                    {
                        Text = s.DisplayName,
                        Value = s.Id.ToString(CultureInfo.InvariantCulture),
                        Selected = selectedSucursalId.HasValue && (s.Id == selectedSucursalId.Value)
                    });
        }

        private void LoadEstadosAfterReceiveOrReturn(Estado? selectedEstado = null)
        {
            this.ViewBag.EstadoList = new[] 
                {
                    CreateEstadoListItem(Estado.DisponibleVenta, selectedEstado),
                    CreateEstadoListItem(Estado.Dañado, selectedEstado)
                };
        }

        private void LoadEstadosAfterAssociate(Estado? selectedEstado = null)
        {
            this.ViewBag.EstadoList = new[] 
                {
                    CreateEstadoListItem(Estado.EnDeposito, selectedEstado),
                    CreateEstadoListItem(Estado.Dañado, selectedEstado)
                };
        }
    }
}
